《剑指offer》 28. 对称的二叉树

note: 所谓对称二叉树,就是以根节点为轴,左右对称的二叉树。

题目描述

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

1
2
3
4
5
    1
/ \
2 2
/ \ / \
3 4 4 3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

1
2
3
4
5
  1
/ \
2 2
\ \
3 3

示例 1:

1
2
输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

1
2
输入:root = [1,2,2,null,3,null,3]
输出:false

限制:

1
0 <= 节点个数 <= 1000

方法 递归

思路

到底什么是对称二叉树,题目描述是和镜像相同,其实本质就是以根节点为轴,左右对称的一棵二叉树。

并不需要每个子树都是对称的(那样就每一层都相同了)。所以我们只需要考虑结点的情况就可以了。

所以我们只需要在使用递归时考虑出下述的递归结构

递归终止条件

  • 要比较的两个节点都为空节点。显然此时返回true

  • 要比较的两个节点有一个为空节点,另一个不为空节点。此时返回false

  • 要比较的两个节点值不相同。此时返回false

递归体

这里是这道题的关键,我们每次递归都要把要进行比较的节点交给下层递归,那么需要如何比较呢?

分析二叉树可以知道,比较的其实是左子树的左节点和右子树的右节点是否相同,以及左子树的右节点和右子树的左节点是否相同。

所以递归体为对左子树左节点、右子树右节点进行递归;对左子树的右节点、右子树的左节点进行递归。

返回结果

显然当左子树的左节点和右子树的右节点相等,且左子树的右节点和右子树的左节点相等时,我们返回真值,否则返回假值。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
bool dfs(TreeNode* L, TreeNode* R){
if(L==NULL && R==NULL)
return true;
if(L==NULL || R==NULL || L->val!=R->val)
return false;
return dfs(L->left,R->right) && dfs(L->right,R->left);
}

public:

bool isSymmetric(TreeNode* root) {
return root==NULL ? true : dfs(root->left, root->right);
}
};

复杂度分析

  • 时间复杂度$O(n)$。需要遍历所有二叉树结点
  • 空间复杂度$O(n)$。进行递归的递归栈深度。